import tkinter as tk
import subprocess
import json
import time
import os

# --- 配置区 ---
BOARD_SIZE = 15
CELL_SIZE = 40  # 棋盘格的大小（像素）
CANVAS_WIDTH = CANVAS_HEIGHT = BOARD_SIZE * CELL_SIZE
JAVA_CLASS_PATH = "."  # Java .class 文件所在的目录，"." 代表当前目录

# AI 默认参数
AI_DEPTH = 2
AI_BRANCHING_FACTOR = 35
# 默认的17个趋势打分系数 (与您提供的默认值一致)
AI_COEFFICIENTS = [
    2.0, 2.0, 2.0, 2.0,  # c1-c4
    2.0, 1.0, 3.0, 5.0, 6.0, 7.0, 8.0, 9.0, 11.0, 13.0, 15.0, # c5-c15
    1.5,  # c16
    0.1   # c17
]

class GameUI:
    def __init__(self, root):
        self.root = root
        self.root.title("对称棋 - 人机对战")

        # 棋盘数据模型 (1: 黑, -1: 白, 0: 空)
        self.board = [[0] * BOARD_SIZE for _ in range(BOARD_SIZE)]

        # 创建主框架
        main_frame = tk.Frame(root)
        main_frame.pack(padx=10, pady=10)

        # 创建棋盘画布
        self.canvas = tk.Canvas(main_frame, width=CANVAS_WIDTH, height=CANVAS_HEIGHT, bg='burlywood')
        self.canvas.pack(side=tk.LEFT)
        self.draw_grid()
        self.canvas.bind("<Button-1>", self.handle_click)

        # 创建控制按钮框架
        control_frame = tk.Frame(main_frame)
        control_frame.pack(side=tk.RIGHT, padx=20)

        # 创建按钮
        self.btn_clear = tk.Button(control_frame, text="清空棋盘", command=self.clear_board, width=15)
        self.btn_clear.pack(pady=10)

        self.btn_ai_black = tk.Button(control_frame, text="AI (黑棋) 行动", command=lambda: self.run_ai(1), width=15)
        self.btn_ai_black.pack(pady=10)

        self.btn_ai_white = tk.Button(control_frame, text="AI (白棋) 行动", command=lambda: self.run_ai(-1), width=15)
        self.btn_ai_white.pack(pady=10)
        
        self.status_label = tk.Label(root, text="请点击棋盘摆棋或让AI行动。", bd=1, relief=tk.SUNKEN, anchor=tk.W)
        self.status_label.pack(side=tk.BOTTOM, fill=tk.X)

    def draw_grid(self):
        """在画布上绘制棋盘网格线"""
        for i in range(BOARD_SIZE):
            self.canvas.create_line(0, i * CELL_SIZE, CANVAS_WIDTH, i * CELL_SIZE)
            self.canvas.create_line(i * CELL_SIZE, 0, i * CELL_SIZE, CANVAS_HEIGHT)

    def draw_pieces(self):
        """根据 self.board 数据绘制所有棋子"""
        self.canvas.delete("piece")  # 删除所有旧棋子
        for r in range(BOARD_SIZE):
            for c in range(BOARD_SIZE):
                if self.board[r][c] != 0:
                    color = 'black' if self.board[r][c] == 1 else 'white'
                    x0 = c * CELL_SIZE + 5
                    y0 = r * CELL_SIZE + 5
                    x1 = (c + 1) * CELL_SIZE - 5
                    y1 = (r + 1) * CELL_SIZE - 5
                    self.canvas.create_oval(x0, y0, x1, y1, fill=color, outline=color, tags="piece")

    def handle_click(self, event):
        """处理鼠标点击棋盘事件，用于手动摆棋"""
        col = event.x // CELL_SIZE
        row = event.y // CELL_SIZE

        if 0 <= row < BOARD_SIZE and 0 <= col < BOARD_SIZE:
            current_state = self.board[row][col]
            # 0 -> 1 -> -1 -> 0 (空 -> 黑 -> 白 -> 空)
            if current_state == 0:
                self.board[row][col] = 1
            elif current_state == 1:
                self.board[row][col] = -1
            else: # current_state == -1
                self.board[row][col] = 0
            self.draw_pieces()
            self.update_status(f"手动在 ({row}, {col}) 修改棋子。")

    def clear_board(self):
        """清空棋盘"""
        self.board = [[0] * BOARD_SIZE for _ in range(BOARD_SIZE)]
        self.draw_pieces()
        self.update_status("棋盘已清空。")

    def run_ai(self, ai_color):
        """调用 Java AI 并根据返回的动作更新棋盘"""
        self.update_status(f"AI ({'黑' if ai_color == 1 else '白'}) 正在计算...")
        self.root.update_idletasks() # 立即更新UI显示状态

        # 1. 将棋盘转换为 Java 需要的字符串格式
        # 'm' 代表 -1 (minus one)，避免命令行解析问题
        board_str = "".join(str(p).replace('-1', 'm') for row in self.board for p in row)

        # 2. 构建命令行参数
        args = [
            "java",
            "-cp", JAVA_CLASS_PATH,
            "Main",
            board_str,
            str(ai_color),
            str(AI_DEPTH),
            str(AI_BRANCHING_FACTOR)
        ] + [str(c) for c in AI_COEFFICIENTS]

        try:
            # 3. 执行 Java 程序并捕获输出
            # 增加 timeout 参数以防 Java 程序卡死
            result = subprocess.run(args, capture_output=True, text=True, check=True, encoding='utf-8', timeout=60)
            output = result.stdout.strip()
            
            # --- 调试代码：打印 Java 的原始输出 ---
            print("--- Java Raw STDOUT ---")
            print(f"'{output}'")
            print("--- End Java Raw STDOUT ---")
            
            if not output:
                raise ValueError("Java process returned an empty string.")

            # 4. 解析 Java 返回的最佳移动
            move = json.loads(output)
            self.update_status("AI 计算完成，正在执行动作...")
            self.execute_move(move, ai_color)

        except subprocess.CalledProcessError as e:
            # 如果 Java 程序返回非零退出码，会触发这个异常
            error_message = f"调用Java AI失败 (Exit Code: {e.returncode})。"
            self.update_status(error_message)
            print(error_message)
            print("--- Java STDERR ---")
            print(e.stderr) # 打印 Java 的标准错误输出
            print("--- End Java STDERR ---")
            
        except subprocess.TimeoutExpired as e:
            error_message = f"调用Java AI超时。"
            self.update_status(error_message)
            print(error_message)
            print("--- Java STDERR (before timeout) ---")
            print(e.stderr)
            print("--- End Java STDERR ---")

        except Exception as e:
            # 其它异常，比如 json.loads 失败
            error_message = f"发生未知错误: {e}"
            self.update_status(error_message)
            print(error_message)

    def execute_move(self, move, color):
        """分步执行AI的动作并更新UI"""
        # move: [place_r, place_c, pull1_src_r, pull1_src_c, pull1_dst_r, pull1_dst_c, pull2_src_r, ...]
        
        actions = []
        # 创建一个临时的棋盘副本，用于模拟动作执行过程
        sim_board = [row[:] for row in self.board]

        # 1. 处理落子动作
        if move[0] != -1:
            place_r, place_c = move[0], move[1]
            actions.append(("place", place_r, place_c, color))
            # 在模拟棋盘上执行落子
            sim_board[place_r][place_c] = color

        # 2. 处理第一次拉子
        if move[2] != -1:
            src_r, src_c = move[2], move[3]
            dst_r, dst_c = move[4], move[5]
            
            # *** 关键修正 ***
            # 从模拟棋盘（sim_board）上获取被拉棋子的颜色。
            # 此时，sim_board 可能已经包含了上一步的落子。
            pull_color = sim_board[src_r][src_c]
            
            if pull_color != 0: # 确保我们不是在拉一个空格子
                actions.append(("pull", src_r, src_c, dst_r, dst_c, pull_color))
                # 在模拟棋盘上执行第一次拉子
                sim_board[src_r][src_c] = 0
                sim_board[dst_r][dst_c] = pull_color
            else:
                # 如果发生这种情况，说明AI的移动逻辑可能有问题，但我们在这里做个保护
                self.update_status(f"警告: AI试图从空位置({src_r}, {src_c})拉子。")

        # 3. 处理第二次拉子
        if move[6] != -1:
            src_r, src_c = move[6], move[7]
            dst_r, dst_c = move[8], move[9]

            # *** 关键修正 ***
            # 再次从模拟棋盘上获取颜色。
            # 此时，sim_board 已经反映了落子和第一次拉子之后的状态。
            pull_color = sim_board[src_r][src_c]

            if pull_color != 0:
                actions.append(("pull", src_r, src_c, dst_r, dst_c, pull_color))
                # 在模拟棋盘上执行第二次拉子 (虽然这里不再需要，但保持逻辑完整)
                sim_board[src_r][src_c] = 0
                sim_board[dst_r][dst_c] = pull_color
            else:
                self.update_status(f"警告: AI试图从空位置({src_r}, {src_c})拉子。")

        # --- 以下的动作执行循环部分保持不变 ---
        def perform_next_action(action_index=0):
            if action_index >= len(actions):
                self.update_status("AI 行动完毕。")
                return

            action = actions[action_index]
            action_type = action[0]

            if action_type == "place":
                r, c, piece_color = action[1], action[2], action[3]
                self.board[r][c] = piece_color
                self.update_status(f"AI 落子于 ({r}, {c})")
            
            elif action_type == "pull":
                src_r, src_c, dst_r, dst_c, piece_color = action[1:]
                self.board[src_r][src_c] = 0  # 移除原位置棋子
                self.board[dst_r][dst_c] = piece_color # 在新位置放置棋子
                self.update_status(f"AI 拉子: ({src_r}, {src_c}) -> ({dst_r}, {dst_c})")

            self.draw_pieces()
            self.root.after(250, lambda: perform_next_action(action_index + 1))

        perform_next_action()

    def update_status(self, message):
        """更新底部的状态栏文本"""
        self.status_label.config(text=message)
        print(message) # 同时在控制台打印，方便调试

if __name__ == "__main__":
    # 确保Java文件已编译
    if not os.path.exists("Main.class") or not os.path.exists("AiController.class"):
        print("警告: 未找到 Main.class 或 AiController.class。")
        print("请先在终端中运行 'javac *.java' 来编译所有Java源文件。")
    
    root = tk.Tk()
    app = GameUI(root)
    root.mainloop()